/**
 * C Implementation: grib_get_keys
 *
 * Description: 
 * how to get values using keys from GRIB messages
 * 利用 key 从 message 中读取数值
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "eccodes.h"

int sfx_grib_get_keys()
{
    int err = 0;

    // create new handle from the first message in the file
    char* filename  = "d:\\temp\\era5-levels-members.grib";
    FILE* in        = fopen(filename, "rb");
    codes_handle* h = codes_handle_new_from_file(NULL, in, PRODUCT_GRIB, &err);
    fclose(in);

    // Store the filename in the key "file" for this handle
    size_t len = strlen(filename);
    CODES_CHECK(codes_set_string(h, "file", filename, &len), 0);

    // get as a long
    long numberOfPointsAlongAParallel;  // 沿一条平行线的点数 (列数)
    CODES_CHECK(codes_get_long(h, "Ni", &numberOfPointsAlongAParallel), 0);
    printf("numberOfPointsAlongAParallel=%ld\n", numberOfPointsAlongAParallel);

    // get as a long
    long numberOfPointsAlongAMeridian;  // 沿子午线的点数 (行数)
    CODES_CHECK(codes_get_long(h, "Nj", &numberOfPointsAlongAMeridian), 0);
    printf("numberOfPointsAlongAMeridian=%ld\n", numberOfPointsAlongAMeridian);

    // get as a double
    double latitudeOfFirstGridPointInDegrees;  // 第一个网格点的纬度（以度为单位）
    CODES_CHECK(codes_get_double(h, "latitudeOfFirstGridPointInDegrees", &latitudeOfFirstGridPointInDegrees), 0);
    printf("latitudeOfFirstGridPointInDegrees=%g\n", latitudeOfFirstGridPointInDegrees);

    // get as a double
    double longitudeOfFirstGridPointInDegrees;  // 第一个网格点的经度（以度为单位）
    CODES_CHECK(codes_get_double(h, "longitudeOfFirstGridPointInDegrees", &longitudeOfFirstGridPointInDegrees), 0);
    printf("longitudeOfFirstGridPointInDegrees=%g\n", longitudeOfFirstGridPointInDegrees);

    // get as a double
    double latitudeOfLastGridPointInDegrees;  // 最后一个网格点的纬度（以度为单位）
    CODES_CHECK(codes_get_double(h, "latitudeOfLastGridPointInDegrees", &latitudeOfLastGridPointInDegrees), 0);
    printf("latitudeOfLastGridPointInDegrees=%g\n", latitudeOfLastGridPointInDegrees);

    // get as a double
    double longitudeOfLastGridPointInDegrees;  // 最后一个网格点的经度（以度为单位）
    CODES_CHECK(codes_get_double(h, "longitudeOfLastGridPointInDegrees", &longitudeOfLastGridPointInDegrees), 0);
    printf("longitudeOfLastGridPointInDegrees=%g\n", longitudeOfLastGridPointInDegrees);

    // get as a double
    double jDirectionIncrementInDegrees;  // j 方向增量（以度为单位）
    CODES_CHECK(codes_get_double(h, "jDirectionIncrementInDegrees", &jDirectionIncrementInDegrees), 0);
    printf("jDirectionIncrementInDegrees=%g\n", jDirectionIncrementInDegrees);

    // get as a double
    double iDirectionIncrementInDegrees;  // i 方向增量（以度为单位）
    CODES_CHECK(codes_get_double(h, "iDirectionIncrementInDegrees", &iDirectionIncrementInDegrees), 0);
    printf("iDirectionIncrementInDegrees=%g\n", iDirectionIncrementInDegrees);

    // get as string
    // 打包类型
    CODES_CHECK(codes_get_length(h, "packingType", &len), 0);
    char* packingType = (char*)malloc(len * sizeof(char));
    CODES_CHECK(codes_get_string(h, "packingType", packingType, &len), 0);
    printf("packingType = %s\n", packingType);
    free(packingType);

    // get the size of the values array
    size_t values_len = 0;
    CODES_CHECK(codes_get_size(h, "values", &values_len), 0);
    double* values = (double*)malloc(values_len * sizeof(double));
    CODES_CHECK(codes_get_double_array(h, "values", values, &values_len), 0);

    // 如果有 missing 呢？
    double average = 0;
    for (int i = 0; i < values_len; i++) {
        average += values[i];
    }
    average /= (double)values_len;

    free(values);

    printf("There are %d values, average is %g\n", (int)values_len, average);

    {
        int eq = -1;
        // Now retrieve the value of the key "file"
        char file[256] = { 0 };
        CODES_CHECK(codes_get_length(h, "file", &len), 0);
        assert(len == 1 + strlen(filename));
        codes_get_string(h, "file", file, &len);
        eq = strcmp(file, filename);
        if (eq != 0) assert(!"file and filename not equal");
    }

    {
        // Example of getting bytes
        const char* name = "reservedNeedNotBePresent";
        size_t keySize   = 0;
        CODES_CHECK(codes_get_size(h, name, &keySize), 0);
        unsigned char* byte_val = (unsigned char*)malloc(keySize * sizeof(unsigned char));
        CODES_CHECK(codes_get_bytes(h, name, byte_val, &keySize), name);
        free(byte_val);
    }

    codes_handle_delete(h);
    return 0;
}
